/**
 * Dictionnaire.java - Dictionnaire du jeu
 * 
 * @author BOURGE Denis && BEGORRE Alexandre
 * @version 1.0
 */

package elements.dictionnaire;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import utils.StringUtils;
import utils.Tuple;

public class Dictionnaire {

	private Map<Character, Integer> nombreLettresDico;
	private Map<Character, Float> frequenceLettresDico;
	private static Map<Character, Integer> nombreJetonsJeu;
	private static Map<Character, Integer> valeurJetonsJeu;
	private List<String> listeMotsDico;							

	public static final int NOMBRE_LETTRES_FINAL = 105;

	private int nombreTotalJetons;
	private int nombreLettres;
	private int jokers;

	private String pathToDico;

	/**
	 * Retourne la map du nombre de jetons
	 * 
	 * @return La map du nombre de jetons
	 */
	public Map<Character, Integer> getNombreJetons() {

		return nombreJetonsJeu;
	}

	/**
	 * Retourne la map de la valeur des jetons
	 * 
	 * @return La map de la valeur des jetons
	 */
	public Map<Character, Integer> getValeurJetons() {

		return valeurJetonsJeu;
	}

	/**
	 * Constructeur du dictionnaire
	 */
	public Dictionnaire() {

		nombreLettresDico = new HashMap<Character, Integer>();
		frequenceLettresDico = new HashMap<Character, Float>();
		nombreJetonsJeu = new HashMap<Character, Integer>();
		valeurJetonsJeu = new HashMap<Character, Integer>();
		listeMotsDico = new ArrayList<String>();

		nombreTotalJetons = 0;
		jokers = 0;
		nombreLettres = 0;
		pathToDico = "";
	}

	/**
	 * Construit la map des fréquences en fonction de la map du nombre de
	 * lettres
	 */
	public void creerMapFrequences() {

		while (!nombreLettresDico.isEmpty()) {
			Tuple<Character, Integer> maxTuple = this.maxFrequence();
			frequenceLettresDico.put(maxTuple.getX(),
					((float) maxTuple.getY() / (float) nombreLettres) * 100);
			nombreLettresDico.remove(maxTuple.getX());
		}
	}

	/**
	 * Retourne le tuple <Lettre, Valeur> de la lettre qui a la plus grande
	 * fréquence
	 * 
	 * @return Le tuple <Lettre, Valeur> de la lettre qui a la plus grande
	 *         fréquence
	 */
	public Tuple<Character, Integer> maxFrequence() {

		Tuple<Character, Integer> monTuple = new Tuple<Character, Integer>(' ',
				-1);

		Iterator<Entry<Character, Integer>> i = nombreLettresDico.entrySet()
				.iterator();
		while (i.hasNext()) {
			Map.Entry<Character, Integer> pairs = i.next();
			if (pairs.getValue() > monTuple.getY()) {
				monTuple.setX(pairs.getKey());
				monTuple.setY(pairs.getValue());
			}
		}

		return monTuple;
	}

	/**
	 * Génère les map de nombre de jetons et des valeurs des jetons en fonction
	 * de la map des fréquences
	 */
	public void genererJetons() {

		Iterator<Entry<Character, Float>> i = frequenceLettresDico.entrySet().iterator();
		while (i.hasNext()) {
			Map.Entry<Character, Float> pairs = i.next();

			if (pairs.getValue() > 10) {
				nombreJetonsJeu.put(pairs.getKey(), 15);
				valeurJetonsJeu.put(pairs.getKey(), 1);
			}

			else if (pairs.getValue() > 8) {
				nombreJetonsJeu.put(pairs.getKey(), 8);
				valeurJetonsJeu.put(pairs.getKey(), 2);
			}

			else if (pairs.getValue() > 5) {
				nombreJetonsJeu.put(pairs.getKey(), 5);
				valeurJetonsJeu.put(pairs.getKey(), 4);
			}

			else if (pairs.getValue() > 2) {
				nombreJetonsJeu.put(pairs.getKey(), 4);
				valeurJetonsJeu.put(pairs.getKey(), 6);
			}

			else if (pairs.getValue() > 1) {
				nombreJetonsJeu.put(pairs.getKey(), 3);
				valeurJetonsJeu.put(pairs.getKey(), 7);
			}

			else if (pairs.getValue() > 0.5) {
				nombreJetonsJeu.put(pairs.getKey(), 2);
				valeurJetonsJeu.put(pairs.getKey(), 8);
			}

			else {
				nombreJetonsJeu.put(pairs.getKey(), 1);
				valeurJetonsJeu.put(pairs.getKey(), 10);
			}
		}

		Iterator<Entry<Character, Integer>> i2 = nombreJetonsJeu.entrySet()
				.iterator();
		nombreTotalJetons = 0;
		while (i2.hasNext()) {
			Map.Entry<Character, Integer> pairs2 = i2.next();
			nombreTotalJetons += pairs2.getValue();
		}

		jokers = NOMBRE_LETTRES_FINAL - nombreTotalJetons;
		if (jokers < 0)
			jokers = 0;
	}

	/**
	 * Compte le nombre de total des lettres et place ça dans nbLettres
	 */
	public void compterNombreTotalLettres() {

		int nbTotal = 0;

		Iterator<Entry<Character, Integer>> i = nombreLettresDico.entrySet()
				.iterator();
		while (i.hasNext()) {
			Map.Entry<Character, Integer> pairs = i.next();
			nbTotal += pairs.getValue();
		}

		nombreLettres = nbTotal;
	}

	/**
	 * Charge un dictionnaire
	 * 
	 * @param pathToFile
	 *            Chemin vers le dictionnaire
	 * @throws FileNotFoundException
	 *             Si le fichier est introuvable
	 */
	public void chargerDictionnaire(String pathToFile)
			throws FileNotFoundException {

		try {
			pathToDico = pathToFile;
			BufferedReader entree = new BufferedReader(new FileReader(
					pathToFile));

			String tmp;

			do {
				tmp = entree.readLine();
				if (tmp != null) {
					String fTmp = StringUtils.normalizeWord(tmp);
					listeMotsDico.add(fTmp);
					for (int i = 0; i < fTmp.length(); i++) {
						char ch = fTmp.charAt(i);
						if (nombreLettresDico.containsKey(ch)) {
							nombreLettresDico.put(ch, nombreLettresDico.get(ch) + 1);
						} else {
							nombreLettresDico.put(ch, 1);
						}
					}
				}
			} while (tmp != null);

			entree.close();
			this.compterNombreTotalLettres();
			this.creerMapFrequences();
		}

		catch (IOException e) {

			e.printStackTrace();
			System.exit(1);
		}
	}
	
	/**
	 * Retourne la liste de mot contenu dans le dictionnaire
	 * 
	 * @return listeMots
	 */
	public List<String> getListeMots() {
		return listeMotsDico;
	}

	/**
	 * Enregistre la map du nombre de lettres dans un fichier externe
	 * 
	 * @param pathToOutput
	 *            Destination
	 * @throws IOException
	 *             Erreur d'I/O
	 */
	public void enregistrerDictionnaire(String pathToOutput) throws IOException {

		PrintWriter sortie = new PrintWriter(new BufferedWriter(new FileWriter(
				pathToOutput)));

		Iterator<Entry<Character, Integer>> i = nombreLettresDico.entrySet()
				.iterator();
		while (i.hasNext()) {
			Map.Entry<Character, Integer> pairs = i.next();
			sortie.println(pairs.getKey() + " = " + pairs.getValue());
		}

		sortie.println("<Total des lettres: " + nombreLettres + ">");

		sortie.close();
	}

	/**
	 * Enregistre la map de la fréquence des lettres dans un fichier externe
	 * 
	 * @param pathToOutput
	 *            Destination
	 * @throws IOException
	 *             Erreur d'I/O
	 */
	public void enregistrerFrequences(String pathToOutput) throws IOException {

		PrintWriter sortie = new PrintWriter(new BufferedWriter(new FileWriter(
				pathToOutput)));

		Iterator<Entry<Character, Float>> i = frequenceLettresDico.entrySet().iterator();
		while (i.hasNext()) {
			Map.Entry<Character, Float> pairs = i.next();
			sortie.println(pairs.getKey() + " = " + pairs.getValue());
		}

		sortie.close();
	}

	/**
	 * Recherche un mot dans la liste de mots
	 * 
	 * @param string
	 *            Mot à chercher
	 * @return Trouvé ou non
	 */
	public boolean chercherMot(String string) {

		return listeMotsDico.contains(string);
	}

	/**
	 * Retourne la valeur de la lettre c
	 * 
	 * @param c
	 *            La lettre
	 * @return La valeur
	 */
	public static int valeurLettre(char c) {

		return valeurJetonsJeu.get(c);
	}

	/**
	 * Retourne la valeur du mot envoyé en paramètre
	 * 
	 * @param mot
	 *            mot
	 * @return
	 */
	public static int valeurMot(String mot) {
		int tmp = 0;
		for (int i = 0; i < mot.length(); ++i)
			tmp += valeurLettre(mot.charAt(i));
		return tmp;
	}

	/**
	 * Retourne le chemin vers le dictionnaire
	 * 
	 * @return Le chemin vers le dictionnaire
	 */
	public String getPathToDico() {

		return pathToDico;
	}

	/**
	 * Fonction principale (de test)
	 * 
	 * @param args
	 *            Arguments en ligne de commande
	 */
	public static void main(String[] args) {

		Dictionnaire d = new Dictionnaire();

		try {
			d.chargerDictionnaire("data/dicos/dico_francais.txt");
			d.enregistrerDictionnaire("data/tables/table_francais.def");
			d.enregistrerFrequences("data/tables/tablepos_francais.def");

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
